package com.ruicar.afs.cloud.batch.dayend.process;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.exception.NacosException;
import com.ruicar.afs.cloud.batch.dayend.handle.run.HandleDataGeneration;
import com.ruicar.afs.cloud.batch.dayend.handle.run.SystemJdbcConfig;
import com.ruicar.afs.cloud.batch.dayend.handle.run.VoucherBean;
import com.ruicar.afs.cloud.batch.frame.AbsBatchRunner;
import com.ruicar.afs.cloud.common.config.VoucherConstant;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.datasync.componts.SyncHelper;
import com.ruicar.afs.cloud.common.enums.VoucherServiceNameEnum;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.WhetherEnum;
import com.ruicar.afs.cloud.common.modules.contract.enums.*;
import com.ruicar.afs.cloud.common.modules.dto.voucher.VoucherBusinessDataDto;
import com.ruicar.afs.cloud.common.modules.dto.voucher.VoucherKeyToQLExpressDto;
import com.ruicar.afs.cloud.common.modules.enums.BusinessType;
import com.ruicar.afs.cloud.common.vo.*;
import com.ruicar.afs.cloud.common.voucher.*;
import com.ruicar.afs.cloud.common.voucher.handle.VoucherCaches;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author infinity
 * @version 1.0
 * @date 2020/8/18 11:48
 */
@Slf4j
public class VoucherGenerationBathRunner extends AbsBatchRunner {
    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(10, 10,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024));
    private HandleDataGeneration handleDataGeneration = SpringContextHolder.getBean(HandleDataGeneration.class);
    private SystemJdbcConfig systemJdbcConfig= SpringContextHolder.getBean(SystemJdbcConfig.class);
    @Override
    public void process(String param) {
        Connection base = this.getConnection();
        logger.info("读取==={}", loadBreakPoint());
        try {
            voucherPublish();
            boolean isFinish = false;
            while (!isFinish) {
                //处理流水信息
                log.info("处理流水信息--开始");
                List<VoucherFlowInfoVo> list = handleVoucherFlowList(VoucherStatusEnum.NOT_CREATED);
                if (CollectionUtil.isNotEmpty(list)) {
                    handleFlows(list);
                } else {
                    isFinish = true;
                }
                log.info("处理流水信息--结束");
            }
            logger.info("读取==={}", loadBreakPoint());
            List<VoucherFlowInfoVo> list = handleVoucherFlowList(VoucherStatusEnum.FAIL_SEND);
            if (CollectionUtil.isNotEmpty(list)) {
                throw new AfsBaseException("凭证底表生成有误！");
            }
        } catch (Exception e) {
            logger.error("", e);
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(base);
        }
    }

    public void handleFlows(List<VoucherFlowInfoVo> list) {
        CountDownLatch countDownLatch = new CountDownLatch(list.size());
        try {
            for (VoucherFlowInfoVo vo : list) {
                EXECUTOR_SERVICE.submit(new FlowVoucherRunner(vo, countDownLatch));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error("", e);
            }
        }
    }

    private void voucherPublish() throws NacosException {
        //加载已生效模板
        List<VoucherInfoVo> voucherInfos = handleVoucherInfoList();
        Map<String, VoucherGroup> voucherGroupMap = new HashMap<>();
        Map<String, VoucherGroup> groupMaps = new HashMap<>();
        Map<String, List<Long>> buriedPointNos = new HashMap<>();
        for (VoucherInfoVo voucherInfo : voucherInfos) {
            List<VoucherEntryVo> entryList = handleVoucherEntryList(voucherInfo.getId());
            if (!groupMaps.containsKey(voucherInfo.getId().toString())) {
                groupMaps.put(voucherInfo.getId().toString(), new VoucherGroup());
                groupMaps.get(voucherInfo.getId().toString()).setInfos(new ArrayList<>());
                VoucherBaseInfo info = new VoucherBaseInfo();
                info.setId(voucherInfo.getId());
                info.setVoucherInfo(voucherInfo);
                info.setEntryList(entryList);
                groupMaps.get(voucherInfo.getId().toString()).getInfos().add(info);
            }
            entryList.forEach(voucherEntry -> {
                if (!voucherGroupMap.containsKey(voucherEntry.getId().toString())) {
                    voucherGroupMap.put(voucherEntry.getId().toString(), new VoucherGroup());
                    voucherGroupMap.get(voucherEntry.getId().toString()).setVouchers(new ArrayList<>());
                    voucherGroupMap.get(voucherEntry.getId().toString()).getVouchers().add(loadVoucher(voucherEntry));
                }
            });
        }
        Map<String, String> voucherCheck = new HashMap<>();
        voucherGroupMap.values().stream().forEach(group -> {
            group.getVouchers().stream().forEach(voucher -> {
                voucherCheck.put(voucher.getRuleNo(), SecureUtil.md5(voucher.getRuleExpress()));
            });
        });
        //查询凭证事件
        handleVoucherTemplateEventsList().forEach(voucherTemplateEvents -> {
            for (VoucherInfoVo voucherInfo : voucherInfos) {
                if (voucherInfo.getMainBusinessCode().equals(voucherTemplateEvents.getMainBusinessCode()) && voucherInfo.getChildBusinessCode().equals(voucherTemplateEvents.getChildBusinessCode())) {
                    if (!buriedPointNos.containsKey(voucherTemplateEvents.getBuriedPointNo())) {
                        List<Long> longs = new ArrayList<>();
                        longs.add(voucherInfo.getId());
                        buriedPointNos.put(voucherTemplateEvents.getBuriedPointNo(), longs);
                    } else {
                        List<Long> longs = buriedPointNos.get(voucherTemplateEvents.getBuriedPointNo());
                        longs.add(voucherInfo.getId());
                        buriedPointNos.put(voucherTemplateEvents.getBuriedPointNo(), longs);
                    }
                }
            }
        });
        if (!voucherCheck.equals(VoucherCaches.getChecks())) {
            //增加凭证信息
            voucherGroupMap.putAll(groupMaps);
            voucherGroupMap.put("events", new VoucherGroup());
            voucherGroupMap.get("events").getEvents().putAll(buriedPointNos);
            JSONObject jsonObject = new JSONObject();
            jsonObject.putAll(voucherGroupMap);
            SyncHelper.publishParams(VoucherConstant.VOUCHER_SYNC_KEY, jsonObject);
        } else {
            log.info("缓存中凭证与发布凭证一致，跳过本次发布.........");
        }
    }

    private Voucher loadVoucher(VoucherEntryVo voucherEntry) {
        Voucher voucher = new Voucher();
        voucher.setRuleNo(voucherEntry.getId().toString());
        VoucherResult voucherResult = new VoucherResult();
        voucherResult.setRuleNo(voucherEntry.getId().toString());
        voucher.setRuleExpress(voucherEntry.getAmountExpression());
        List<VoucherAtomMapping> voucherAtomMappings = handleAtomMappingList(voucherEntry.getId());
        voucher.setVoucherAtomMappings(voucherAtomMappings);
        return voucher;
    }

    public List<VoucherInfoVo> handleVoucherInfoList() {
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        StringBuffer sql = new StringBuffer();
        sql.append("select info.id,info.main_business,info.main_business_code,info.child_business,info.child_business_code ");
        sql.append(",info.description,info.data_sources from voucher_info info where info.status=?  and info.del_flag='0'");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<VoucherInfoVo> list = new ArrayList<VoucherInfoVo>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setString(1, AfsEnumUtil.key(VoucherStatus.ACTIVE));
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                VoucherInfoVo vo = new VoucherInfoVo();
                vo.setId(rs.getLong("id"));
                vo.setMainBusiness(rs.getString("main_business"));
                vo.setMainBusinessCode(rs.getString("main_business_code"));
                vo.setChildBusiness(rs.getString("child_business"));
                vo.setChildBusinessCode(rs.getString("child_business_code"));
                vo.setDescription(rs.getString("description"));
                if (StringUtil.isNotBlank(rs.getString("data_sources"))) {
                    vo.setDataSources((VoucherDataSources) AfsEnumUtil
                            .getEnum(rs.getString("data_sources"), VoucherDataSources.class));
                }
                list.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
            clean(contractAcount);
        }
        return list;
    }

    public List<VoucherEntryVo> handleVoucherEntryList(Long id) {
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        StringBuffer sql = new StringBuffer();
        sql.append("select entry.id,entry.lending_direction,entry.subject_code,entry.subject_name,entry.amount_expression ");
        sql.append(",entry.order_num,entry.explanation ,entry.correlation_id, entry.rule_no from voucher_entry entry   ");
        sql.append(" where entry.correlation_id=?  and entry.del_flag='0'");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<VoucherEntryVo> list = new ArrayList<VoucherEntryVo>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setLong(1, id);
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                VoucherEntryVo vo = new VoucherEntryVo();
                vo.setId(rs.getLong("id"));
                if (StringUtil.isNotBlank(rs.getString("lending_direction"))) {
                    vo.setLendingDirection((LendingDirection) AfsEnumUtil
                            .getEnum(rs.getString("lending_direction"), LendingDirection.class));
                }
                vo.setSubjectCode(rs.getString("subject_code"));
                vo.setSubjectName(rs.getString("subject_name"));
                vo.setAmountExpression(rs.getString("amount_expression"));
                vo.setOrderNum(rs.getInt("order_num"));
                vo.setExplanation(rs.getString("explanation"));
                vo.setCorrelationId(rs.getLong("correlation_id"));
                vo.setRuleNo(rs.getLong("rule_no"));
                list.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
            clean(contractAcount);
        }
        return list;
    }

    public List<VoucherAtomMapping> handleAtomMappingList(Long id) {
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        StringBuffer sql = new StringBuffer();
        sql.append("select mapping.value_express,mapping.atom_key,mapping.mapping_key,mapping.atom_type  ");
        sql.append(" from voucher_rule_input_mapping mapping  where mapping.rule_id=? and mapping.del_flag='0' ");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<VoucherAtomMapping> list = new ArrayList<VoucherAtomMapping>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setLong(1, id);
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                VoucherAtomMapping voucherAtomMapping = new VoucherAtomMapping();
                voucherAtomMapping.setValuePath(rs.getString("value_express"));
                voucherAtomMapping.setAtomKey(rs.getString("atom_key"));
                voucherAtomMapping.setMappingName(rs.getString("mapping_key"));
                if (StringUtil.isNotBlank(rs.getString("atom_type"))) {
                    voucherAtomMapping.setAtomType((AtomComponentType) AfsEnumUtil
                            .getEnum(rs.getString("atom_type"), AtomComponentType.class));
                }
                list.add(voucherAtomMapping);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
            clean(contractAcount);
        }
        return list;
    }

    public List<VoucherTemplateEventsVo> handleVoucherTemplateEventsList() {
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        StringBuffer sql = new StringBuffer();
        sql.append("select event.main_business_code,event.child_business_code,event.buried_point_no   ");
        sql.append(" from voucher_template_events event  where event.status=? and event.del_flag='0' ");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<VoucherTemplateEventsVo> list = new ArrayList<VoucherTemplateEventsVo>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setString(1, AfsEnumUtil.key(VoucherStatus.ACTIVE));
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                VoucherTemplateEventsVo vo = new VoucherTemplateEventsVo();
                vo.setMainBusinessCode(rs.getString("main_business_code"));
                vo.setChildBusinessCode(rs.getString("child_business_code"));
                vo.setBuriedPointNo(rs.getString("buried_point_no"));
                list.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
            clean(contractAcount);
        }
        return list;
    }

    @AllArgsConstructor
    class FlowVoucherRunner implements Runnable {
        private VoucherFlowInfoVo vo;
        private CountDownLatch countDownLatch;
        @Override
        public void run() {
            try {
                handleFlowingWater(vo);
            } catch (Exception e) {
                log.error("", e);
                updateFlowInfo(vo.getId(), e.getMessage());
            } finally {
                countDownLatch.countDown();
            }
        }
    }
    public void handleFlowingWater(VoucherFlowInfoVo voucherFlowInfo) {
        //根据埋点编号获取凭证事件相对应模板id
        List<Long> ids = VoucherCaches.getEvents(voucherFlowInfo.getBuriedPointNo());
        Map<VoucherDataSources, List<Long>> map = new HashMap<>();
        //相同的收据来源的凭证事件组装在一起
        for (Long id : ids) {
            VoucherBaseInfo info = VoucherCaches.getVoucherInfo(id);
            if (!map.containsKey(info.getVoucherInfo().getDataSources())) {
                List<Long> longs = new ArrayList<>();
                longs.add(id);
                map.put(info.getVoucherInfo().getDataSources(), longs);
            } else {
                List<Long> longs = map.get(info.getVoucherInfo().getDataSources());
                longs.add(id);
                map.put(info.getVoucherInfo().getDataSources(), longs);
            }
        }
        Connection connection = null;
        List<VoucherAccountVo> voucherAccountVos = new ArrayList<>();
        Iterator it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            VoucherDataSources dataSources = (VoucherDataSources) entry.getKey();
            List<Long> longList = (List<Long>) entry.getValue();
            VoucherBean bean = handleDataGeneration.getVoucherParam(voucherFlowInfo, longList);
            switch (dataSources) {
                case CASE_SERVICE:
                    connection = this.getConnection(systemJdbcConfig.getCaseServer());
                    getAmt(bean.getVoucherBusinessDataDto(), connection);
                    bean.setSourceSystem( AfsEnumUtil.key( VoucherServiceNameEnum.BOSS ) );
                    break;
                case CONTRACT_SERVICE:
                    connection = this.getConnection(systemJdbcConfig.getBasic());
                    getAmt(bean.getVoucherBusinessDataDto(), connection);
                    bean.setSourceSystem( AfsEnumUtil.key( VoucherServiceNameEnum.ICOS ) );
                    break;
                case FINANCE_SERVICE:
                    connection = this.getConnection(systemJdbcConfig.getFinance());
                    getAmt(bean.getVoucherBusinessDataDto(), connection);
                    bean.setSourceSystem( AfsEnumUtil.key( VoucherServiceNameEnum.ICOS ) );
                    break;
                case MANAGE_SERVICE:
                    connection = this.getConnection(systemJdbcConfig.getManage());
                    getAmt(bean.getVoucherBusinessDataDto(), connection);
                    bean.setSourceSystem( AfsEnumUtil.key( VoucherServiceNameEnum.ICOS ) );
                    break;
                default:
                    log.error("凭证数据来源：[{}]，凭证方法未实现", AfsEnumUtil.desc(dataSources));
                    throw new AfsBaseException("凭证数据来源：[{}]，凭证方法未实现", AfsEnumUtil.desc(dataSources));
            }
            List<VoucherAccountVo> vos = handleDataGeneration.saveVoucherInfo(bean.getVoucherBusinessDataDto(),bean);
            if (CollectionUtil.isNotEmpty(vos)) {
                voucherAccountVos.addAll(vos);
            }
        }
        this.saveVoucher(voucherAccountVos, voucherFlowInfo);
    }

    private VoucherBusinessDataDto getAmt(VoucherBusinessDataDto dto, Connection connection) {
        ResultSet rs = null;
        PreparedStatement queryPs = null;
        try {
            for (VoucherKeyToQLExpressDto voucherKeyToQLExpressDto : dto.getVoucherKeyToQLExpressDtos()) {
                queryPs = connection.prepareStatement(voucherKeyToQLExpressDto.getQlExpress());
                rs = queryPs.executeQuery();
                BigDecimal amt = BigDecimal.ZERO;
                while (rs != null && rs.next()) {
                    amt = rs.getBigDecimal(1);
                }
                voucherKeyToQLExpressDto.setAmt(amt);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(queryPs);
            clean(rs);
            clean(connection);
        }
        return dto;
    }

    public List<VoucherFlowInfoVo> handleVoucherFlowList(VoucherStatusEnum status) {
        Connection contractAcount = this.getConnection(systemJdbcConfig.getAccount());
        StringBuffer sql = new StringBuffer();
        sql.append("select flow.id,flow.trans_no,flow.buried_point_no,flow.contract_no,flow.status ");
        sql.append(",flow.car_brand,flow.financial_products,flow.department,flow.dealer_name ");
        sql.append(",flow.business_type,flow.keep_account_date,flow.daily_cut_time from  voucher_flow_info flow where status=?");
        sql.append(" order by flow.id asc ");
        sql.append("  limit 0, ? ");
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<VoucherFlowInfoVo> list = new ArrayList<VoucherFlowInfoVo>();
        try {
            ps = contractAcount.prepareStatement(sql.toString());
            ps.setString(1, AfsEnumUtil.key(status));
            ps.setInt(2, VoucherConstant.batchesSize);
            rs = ps.executeQuery();
            while (rs != null && rs.next()) {
                VoucherFlowInfoVo vo = new VoucherFlowInfoVo();
                vo.setId(rs.getLong("id"));
                vo.setContractNo(rs.getString("contract_no"));
                vo.setTransNo(rs.getString("trans_no"));
                vo.setBuriedPointNo(rs.getString("buried_point_no"));
                vo.setCarBrand(rs.getString("car_brand"));
                vo.setFinancialProducts(rs.getString("financial_products"));
                vo.setDepartment(rs.getString("department"));
                vo.setDealerName(rs.getString("dealer_name"));
                vo.setKeepAccountDate(rs.getDate("keep_account_date"));
                if (StringUtil.isNotBlank(rs.getString("business_type"))) {
                    vo.setBusinessType((BusinessType) AfsEnumUtil
                            .getEnum(rs.getString("business_type"), BusinessType.class));
                }
                list.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(rs);
            clean(contractAcount);
        }
        return list;
    }

    /*
     * 写入凭证信息
     *
     * @return
     */
    private void saveVoucher(List<VoucherAccountVo> voucherAccountVos, VoucherFlowInfoVo voucherFlowInfo) {
        Connection connection = this.getConnection(systemJdbcConfig.getAccount());
        Date batchDate = new Date(batchDateInfo.getBatchDate().getTime());
        StringBuffer sql = new StringBuffer();
        sql.append("insert into account_voucher_info(id,voucher_no,contract_no,dealer_name,voucher_serial_number, ");
        sql.append(" fiscal_year, accounting_period ,explanation ,total_amount,prepared_date,posting_date,status , ");
        sql.append(" main_business, main_business_code ,child_business ,child_business_code,business_no,reversal_voucher_no,source_system,create_by,create_time ) ");
        sql.append("values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
        StringBuffer sqlEntry = new StringBuffer();
        sqlEntry.append("insert into account_voucher_entry(id,voucher_no,entry_no,subject_code,subject_name, ");
        sqlEntry.append(" lending_direction, debit_amt ,credit_amt ,explanation,create_by,create_time ) ");
        sqlEntry.append("values(?,?,?,?,?,?,?,?,?,?,?)");
        StringBuffer sqlFlow = new StringBuffer();
        sqlFlow.append("update voucher_flow_info set status =? where id =? and status=? ");
        PreparedStatement ps = null;
        try {
            //保存凭证主信息
            ps = connection.prepareStatement(sql.toString());
            saveAccountInfo(ps, voucherAccountVos, voucherFlowInfo,batchDate);
            //保存凭证分录信息
            ps = connection.prepareStatement(sqlEntry.toString());
            saveAccountEntry(ps, voucherAccountVos,batchDate);
            //修改凭证流水状态
            ps = connection.prepareStatement(sqlFlow.toString());
            ps.setString(1, AfsEnumUtil.key(VoucherStatusEnum.CREATED));
            ps.setLong(2, voucherFlowInfo.getId());
            ps.setString(3, AfsEnumUtil.key(VoucherStatusEnum.NOT_CREATED));
            ps.addBatch();
            ps.executeBatch();
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            throw new AfsBaseException(e.getMessage());
        } finally {
            clean(ps);
            clean(connection);
        }
    }

    //保存凭证主信息
    private void saveAccountInfo(PreparedStatement ps, List<VoucherAccountVo> list, VoucherFlowInfoVo voucherFlowInfo, Date batchDate) throws SQLException {
        if (list != null && list.size() > 0) {
            for (VoucherAccountVo vo : list) {
                ps.setLong(1, vo.getAccountVoucherInfoVo().getId());
                ps.setString(2, vo.getAccountVoucherInfoVo().getVoucherNo());
                ps.setString(3, voucherFlowInfo.getContractNo());
                ps.setString(4, voucherFlowInfo.getDealerName());
                ps.setString(5, vo.getAccountVoucherInfoVo().getVoucherNo());
                ps.setString(6, vo.getAccountVoucherInfoVo().getFiscalYear());
                ps.setString(7, vo.getAccountVoucherInfoVo().getAccountingPeriod());
                ps.setString(8, vo.getAccountVoucherInfoVo().getChildBusiness());
                ps.setBigDecimal(9, vo.getAccountVoucherInfoVo().getTotalAmount());
                ps.setDate(10, voucherFlowInfo.getKeepAccountDate()!=null?new java.sql.Date(vo.getAccountVoucherInfoVo().getPreparedDate().getTime()):null);
                ps.setDate(11, voucherFlowInfo.getKeepAccountDate()!=null?new java.sql.Date(voucherFlowInfo.getKeepAccountDate().getTime()):null);
                ps.setString(12, AfsEnumUtil.key(VoucherSendStatus.NOT_SEND));
                ps.setString(13, vo.getAccountVoucherInfoVo().getMainBusiness());
                ps.setString(14, vo.getAccountVoucherInfoVo().getMainBusinessCode());
                ps.setString(15, vo.getAccountVoucherInfoVo().getChildBusiness());
                ps.setString(16, vo.getAccountVoucherInfoVo().getChildBusinessCode());
                ps.setString(17, vo.getAccountVoucherInfoVo().getBusinessNo());
                ps.setString(18, AfsEnumUtil.key(WhetherEnum.NO));
                ps.setString(19, vo.getAccountVoucherInfoVo().getSourceSystem());
                ps.setString(20, "system");
                ps.setDate(21, batchDate);
                ps.addBatch();
            }
            ps.executeBatch();
        }
    }

    //保存凭证分录信息
    private void saveAccountEntry(PreparedStatement ps, List<VoucherAccountVo> list,Date batchDate) throws SQLException {
        if (list != null && list.size() > 0) {
            for (VoucherAccountVo vo : list) {
                for (AccountVoucherEntryVo accountVoucherEntryVo : vo.getAccountVoucherEntryVos()) {
                    ps.setLong(1, accountVoucherEntryVo.getId());
                    ps.setString(2, accountVoucherEntryVo.getVoucherNo());
                    ps.setInt(3, accountVoucherEntryVo.getEntryNo());
                    ps.setString(4, accountVoucherEntryVo.getSubjectCode());
                    ps.setString(5, accountVoucherEntryVo.getSubjectName());
                    ps.setString(6, AfsEnumUtil.key(accountVoucherEntryVo.getLendingDirection()));
                    ps.setBigDecimal(7, accountVoucherEntryVo.getDebitAmt());
                    ps.setBigDecimal(8, accountVoucherEntryVo.getCreditAmt());
                    ps.setString(9, accountVoucherEntryVo.getExplanation());
                    ps.setString(10, "system");
                    ps.setDate(11, batchDate);
                    ps.addBatch();
                }
            }
            ps.executeBatch();
        }
    }

    private void updateFlowInfo(Long id, String errMsg) {
        StringBuffer sqlFlow = new StringBuffer();
        sqlFlow.append("update voucher_flow_info set status =? ,err_msg =? where id =? and status=? ");

        //修改凭证流水状态
        PreparedStatement ps = null;
        Connection connection = this.getConnection(systemJdbcConfig.getAccount());
        try {
            ps = connection.prepareStatement(sqlFlow.toString());
            ps.setString(1, AfsEnumUtil.key(VoucherStatusEnum.FAIL_CREATED));
            ps.setString(2, errMsg);
            ps.setLong(3, id);
            ps.setString(4, AfsEnumUtil.key(VoucherStatusEnum.NOT_CREATED));
            ps.execute();
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            clean(ps);
            clean(connection);
        }
    }
}
